package fi.uba.tecnicas.diseno.tp2.ui;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import json.IReader;
import modelo.Cupon;
import modelo.Oferta;
import modelo.OrdenDeCompra;
import modelo.Producto;
import modelo.Venta;
import modelo.query.InvalidQueryException;
import modelo.query.QueryTranslator;
import modelo.reglas.composite.inner.GroupSpecification;
import modelo.reglas.engine.BestSell;
import modelo.reglas.engine.Seller;
import context.TpContextFactory;

/**
 * 
 * @author federico
 */

public class RegisterBox {
	SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy", Locale.getDefault());
	SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm", Locale.getDefault());

	private static TpContextFactory cf;

	private Integer ticketNumber = new Integer(0);
	private Integer number;

	private boolean isOpen = false;
	private boolean isInit = false;
	private String branchOffice;
	private Date date = Calendar.getInstance().getTime();
	private String clientType;
	private String payment;
	private String bank;
	private boolean generateCupon = false;
	private Cupon generatedCupon;
	private List<Producto> productsPurchased = new ArrayList<Producto>();
	private List<Cupon> discountCuponsList = new ArrayList<Cupon>();
	private BigDecimal subtotal = new BigDecimal(0).setScale(2, BigDecimal.ROUND_HALF_UP);
	private BigDecimal total = new BigDecimal(0).setScale(2, BigDecimal.ROUND_HALF_UP);
	private BigDecimal discountsTotal = new BigDecimal(0).setScale(2, BigDecimal.ROUND_HALF_UP);

	public RegisterBox(Integer number, String branchOffice) {
		super();
		this.number = number;
		this.branchOffice = branchOffice;

		cf = new TpContextFactory();
		cf.init();
	}

	public void openRegisterBox() {
		if (!isOpen && !isInit) {
			isOpen = true;
		}
	}

	public void closeRegisterBox() {
		if (isOpen && !isInit) {
			isOpen = false;
		}
	}

	public boolean initPurchase(String payment, String bank, String clientType) {
		boolean result = false;
		if (isOpen && !isInit) {
			ticketNumber++;
			isInit = true;
			this.payment = payment;
			this.bank = bank;
			this.clientType = clientType;
		}
		return result;
	}

	public boolean finalizePurchase() {
		boolean result = false;
		if (isOpen && isInit) {
			productsPurchased.clear();
			isInit = false;
		}
		return result;
	}

	public OrdenDeCompra generatePurchaseOrder() {
		OrdenDeCompra result = null;
		if (!productsPurchased.isEmpty()) {
			result = new OrdenDeCompra(productsPurchased, Calendar.getInstance().getTime(), payment, bank, getCurrentDay(), clientType);
		}
		return result;
	}

	public Venta generateSell(OrdenDeCompra purchaseOrder) {
		IReader dataBase = cf.getDbReader();
		Venta sellResult = null;
		if (isInit) {
			try {
				List<Oferta> calculateBestOffersOrdering = BestSell.calculateBestOffersOrdering(dataBase.readOfferProducts(), purchaseOrder);
				Map<Oferta, List<Producto>> productOfferAppliedList = Seller
						.obtainApplingOffersToBuyOrder(calculateBestOffersOrdering, purchaseOrder);

				if (productOfferAppliedList == null) {
					productOfferAppliedList = new HashMap<Oferta, List<Producto>>();
				}
				List<Oferta> sellOfferAppliedList = new ArrayList<Oferta>();
				Oferta sellOfferApplied = BestSell.calculateBestSellOffert(dataBase.readOfferSell(), purchaseOrder);

				if (sellOfferApplied != null) {
					sellOfferAppliedList.add(sellOfferApplied);
				}

				List<Oferta> ofertaList = new ArrayList<Oferta>(productOfferAppliedList.keySet());

				sellResult = new Venta(purchaseOrder, ofertaList, sellOfferAppliedList, discountCuponsList, generateCupon);
				generatedCupon = sellResult.getCuponGenerado();

				if (generatedCupon != null) {
					ArrayList<Cupon> cuponsList = (ArrayList<Cupon>) cf.getDbReader().readCupons();
					cuponsList.add(generatedCupon);
					cf.getDbWriter().writeCupons(cuponsList);
				}

				total = sellResult.getPrecioFinal().setScale(2, BigDecimal.ROUND_HALF_UP);
				subtotal = sellResult.getSubtotal().setScale(2, BigDecimal.ROUND_HALF_UP);
				discountsTotal = sellResult.getDescuentos().setScale(2, BigDecimal.ROUND_HALF_UP);

				List<Venta> ventasTotales = cf.getDbReader().readSells();

				ventasTotales.add(sellResult);
				cf.getDbWriter().writeSells(ventasTotales);

			} catch (InvalidQueryException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return sellResult;
	}

	public Cupon addCupon(String cuponId) {
		Cupon cupon = null;
		if (isInit) {
			cupon = obtainDiscountCupon(cuponId);
			if (cupon != null) {
				discountCuponsList.add(cupon);
			}
		}
		return cupon;
	}

	public Producto addProduct(String productId) {
		Producto product = null;
		if (isInit) {
			product = searchProduct(productId);
			if (product != null) {
				productsPurchased.add(product);
			}
		}
		return product;
	}

	public Cupon obtainDiscountCupon(String cuponId) {
		IReader dataBase = cf.getDbReader();
		Cupon result = null;
		try {
			List<Cupon> cuponsList = dataBase.readCupons();
			Iterator<Cupon> it = cuponsList.iterator();
			boolean cuponFound = false;
			while (it.hasNext() && !cuponFound) {
				Cupon cupon = it.next();
				if (cupon.getCodigo().equals(cuponId)) {
					result = cupon;
					cuponFound = true;
					cuponsList.remove(cupon);
					cf.getDbWriter().writeCupons(cuponsList);
				}
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return result;
	}

	public Cupon removeCupon(String cuponId) {
		Cupon cupon = obtainDiscountCupon(cuponId);
		if (isInit && cupon != null) {
			discountCuponsList.remove(cupon);
		}
		return cupon;
	}

	public Producto removeProduct(String productId) {
		Producto product = searchProduct(productId);
		if (isInit && product != null) {
			productsPurchased.remove(product);
		}
		return product;
	}

	public Producto searchProduct(String productId) {
		IReader dataBase = cf.getDbReader();
		Producto productResult = null;
		try {
			QueryTranslator queryTranslator = new QueryTranslator();
			List<Producto> productsList;
			productsList = dataBase.readProducts();
			String queryProductId = "AND(Id=" + productId + ",Id=" + productId + ")";
			GroupSpecification<Producto> queryProductResult = queryTranslator.translateQueryForProduct(queryProductId);
			queryProductResult.isSatisfiedBy(productsList);
			List<Producto> productsResultList = queryProductResult.getElementosQueCumplen();
			if (!productsResultList.isEmpty()) {
				productResult = productsResultList.get(0);
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidQueryException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return productResult;
	}

	private String getCurrentDay() {
		String result = null;
		switch (Calendar.getInstance().get(Calendar.DAY_OF_WEEK)) {
		case Calendar.SUNDAY:
			result = "Domingo";
			break;
		case Calendar.MONDAY:
			result = "Lunes";
			break;
		case Calendar.TUESDAY:
			result = "Martes";
			break;
		case Calendar.WEDNESDAY:
			result = "Miercoles";
			break;
		case Calendar.THURSDAY:
			result = "Jueves";
			break;
		case Calendar.FRIDAY:
			result = "Viernes";
			break;
		case Calendar.SATURDAY:
			result = "Sabado";
			break;
		default:
			result = "";
		}
		return result;
	}

	public String isInit() {
		return isInit();
	}

	public String getBranchOffice() {
		return branchOffice;
	}

	public void setBranchOffice(String branchOffice) {
		this.branchOffice = branchOffice;
	}

	public String getPayment() {
		return payment;
	}

	public void setPayment(String payment) {
		this.payment = payment;
	}

	public String getBank() {
		return bank;
	}

	public void setBank(String bank) {
		this.bank = bank;
	}

	public String getClientType() {
		return clientType;
	}

	public void setClientType(String clientType) {
		this.clientType = clientType;
	}

	public Integer getTicketNumber() {
		return ticketNumber;
	}

	public Integer getNumber() {
		return number;
	}

	public Date getDate() {
		return date;
	}

	public String getDateFormatted() {
		return dateFormat.format(date);
	}

	public BigDecimal getSubtotal() {
		return subtotal;
	}

	public BigDecimal getTotal() {
		return total;
	}

	public BigDecimal getDiscountsTotal() {
		return discountsTotal;
	}

	public void setGenerateCupon(boolean generateCupon) {
		this.generateCupon = generateCupon;
	}

	public boolean isGenerateCupon() {
		return generateCupon;
	}

	public Cupon getGeneratedCupon() {
		return generatedCupon;
	}

}
